package JUC.AtomicLeiAPI;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author CKC
 * @DateTime 2021/6/3 20:48
 * <p>
 * API的介绍
 * AtomicIntegerArray
 * AtomicLongArray
 * AtomicRefernceArray
 */
public class AtomicArrayDemo {
    public static void main(String[] args) {
        //不安全的数组
        demo(
                ()->new int[10],
                (array)->array.length,
                (array,index)->array[index]++,
                array-> System.out.println(Arrays.toString(array))
        );
        System.out.println("---------------------------");
        
        //安全的数组
        demo(
                ()->new AtomicIntegerArray(10), (array)->array.length(),
                (array,index)->array.getAndIncrement(index),
                array-> System.out.println(array)
        );
        
        //流式编程？  跟上面一样
        demo(
                ()->new AtomicIntegerArray(10), AtomicIntegerArray::length,
                AtomicIntegerArray::getAndIncrement,
                System.out::println
        );
    }
    
    
    /**
     * 函数式接口说明
     * Supplier 提供者    无中生有 ()->结果
     * Function 函数  一个参数一个结果    (参数)-> 结果,  BiFunction (参数1,参数2)-> 结果
     * Consumer 消费者  一个参数没有结果  (参数)-> void, BiConsumer (参数1,参数2)-> void
     *
     * demo方法参数的作用：
     * 参数一：提供数组，可以是线程安全或不安全数组
     * 参数二：获取数组长度的方法
     * 参数三：自增方法 ，回传 array，index
     * 参数四：打印数组的方法
     *
     */
    private static <T> void demo(Supplier<T> arraySupplier, Function<T, Integer> lengFun,
            BiConsumer<T, Integer> putConsumer, Consumer<T> printConsumer) {
        List<Thread> ts = new ArrayList<>();
        
        T array = arraySupplier.get();
        
        int length = lengFun.apply(array);
        for (int i = 0; i < length; i++) {
            ts.add(new Thread(() -> {
                
                //每个线程对数组作 10000次 操作
                for (int j = 0; j < 10000; j++) {
                    putConsumer.accept(array, j % length);
                }
            }));
        }
        
        ts.forEach(Thread::start); //启动线程
        ts.forEach(t->{
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });//等待所有线程结束
        
        printConsumer.accept(array);
        
    }
}

